/********************************************************************************/
/*ソース名:                                                                       */
/*　　pf_mem.c                                                                    */
/*機能:                                                                         */
/*　　 メモリを管理する                    　　　　　　　　　　　　　　　　                                                                                     */
/*作成者:                                                                       */
/*　　2010/02 関（CBSﾃｸﾉ）                                                                                                                                       */
/********************************************************************************/
/*変更履歴:                                                                     */
/*　2010/02　関　　新規作成                                                                                                                                    */
/********************************************************************************/
#include <stdio.h>
#include <string.h>
#include <stdarg.h>
#include <stdlib.h>
#include <ctype.h>
#include <string.h>
#include <time.h>
#include <errno.h>
#include "typedef.h"
#include "Id.h"
#include "lib_func.h"
#include "core.h"
#include "./textfile/pf_file.h"
#include "./memory/mem_interface.h"
#include "pf_mem.h"
#if FLG_BIT_NUM >= 0

/*
 * このモジュールでは、Multi－Threadで使用してはいけない
 */
/* 内部メモリブロック管理用*/
/**************************************
 * マクロ
 */
#define SetErrCode(usKind, usIdx, code)   (ulMemComErrCode = ((U4)usKind<<MEMERR_KINDBIT)|((U4)usIdx<<MEMERR_MODIDXBIT)|((U4)code<<MEMERR_CODEBIT))
#define _BLOCK_HEADER_STRING_  "__BLK_HEAD__"
#define gblBlock_size  (BLOCK_SIZE - HEADER_SIZE )
#define owner_buffer_alloc_size    (1UL<<12)   /* 4KB */
#define owner_buffer_size    (owner_buffer_alloc_size - ownbuf_headersize)
#define owner_validation_key   '@'
#define owner_name_max_length  60
#define ownbuf_headersize  (sizeof( owner_buffer_header ))

#define BLOCK_BUSY  1
#define BLOCK_IDLE  2
#define BLOCK_LAZY  3
typedef struct __OWNER_BUFFER{
	struct __OWNER_BUFFER * next;
	CHAR * buffer;
}owner_buffer_header;
/* 各サイズの管理用情報  */
static page_size_info 				page_info[FLG_BIT_NUM+1];
/* 配分したブロックを管理   */
static 								block_manager blocks;
/* 最低限メモリ    */
static U4 							max_mem_volumn = MIN_MEM_SIZE ;
/* 現在のメモリ    */
static U4 							cur_mem_volumn = 0 ;

static U4 							cur_mem_in_use = 0 ;
/* 初期化済みフラグ   */
static UCHAR 						initial_flag=0;
/* メモリ使用情報を記録するかのフラグ   */
static  UCHAR 						gblRecordTableByte = 0;
/* swap_outを起こしたか */
static  S4						lSwapOutCnt = 0;
/* owner 名を保存するバッファー   */
static  owner_buffer_header * 		owner_buffer=NULL;
/* バッファー使用量   */
static  U4						ownBufOffset=0;
static  U4 						ownerNum=0;
/* swap out 先    */
static CHAR	szPath[OS_FULLPATH+4];
static CHAR	szFilePath[OS_FULLPATH+4];
static CHAR	szName[100];
static CHAR	szName_Prefix[50];


static BOOL	resetmemory( VOID );
static BOOL	allocmemory( VOID **ppvArea, U4 ulSize );
static BOOL new_page( S2 idx, VOID ** page );
static BOOL new_block(  VOID ** page );
static BOOL free_page( page_header* page );
static BOOL free_block( page_header* page );
static BOOL move_block( page_header* page );
static BOOL move_page_inuse( page_header* page );
static BOOL	file2data( VOID	*page,  CHAR * pszFile, U4 ulSize );
static BOOL	data2file( CHAR * pszFile, VOID	*page, U4 ulSize );
static VOID InformReset( buffer_owner_info * p_owner );
static owner_buffer_header * newOwnerPage( VOID );

static void addBlock( page_header *block, U2 flag  ){
	page_header *temp;

	if( block != NULL ){
		block->block_flag = flag;
		switch( flag ){
		case BLOCK_BUSY :
			temp = blocks.blk_in_use;
			blocks.blk_in_use = block;
			block->next_block = temp;
			if( temp != NULL && blocks.blk_in_use_cnter > 0 ){
				temp->pre_block = block;
			}
			blocks.blk_in_use_cnter++;
			break;
		case BLOCK_IDLE :
			temp = blocks.blk_idle;
			blocks.blk_idle = block;
			block->next_block = temp;
			if( temp != NULL && blocks.blk_idle_cnter > 0 ){
				temp->pre_block = block;
			}
			blocks.blk_idle_cnter++;
			break;
		case BLOCK_LAZY :
			temp = blocks.blk_old;
			blocks.blk_old = block;
			block->next_block = temp;
			if( temp != NULL && blocks.blk_old_cnter > 0 ){
				temp->pre_block = block;
			}
			blocks.blk_old_cnter++;
			break;
		}
	}
}
/**************************************************************************
* 関 数 名 : move_block
* 機    能 : 双方向チェーンからブロックを取り除く
* 引 き 数 : page_header* block ブロックの管理情報へのポインタ
* 戻 り 値 : BOOL        1              正常終了
*          :          0             異常終了
************************************************************************/
static BOOL move_block( page_header* block )
{
	page_header * temp;
	move_page_inuse(block);
	if( block != NULL )
	{
		switch( block->block_flag ){
		case BLOCK_BUSY :
			if( blocks.blk_in_use_cnter > 0 ){
				temp = ( page_header* )block->pre_block;
				if( temp != NULL ){
					temp->next_block = block->next_block;
					temp = block->next_block;
					if( temp != NULL  ){
						temp->pre_block = block->pre_block;
					}
				}else{
					blocks.blk_in_use = block->next_block;
					if( blocks.blk_in_use ){
						((page_header  *)blocks.blk_in_use)->pre_block = NULL;
					}
				}
				blocks.blk_in_use_cnter--;
			}
			break;
		case BLOCK_IDLE :
			if( blocks.blk_idle_cnter > 0 ){
				temp = ( page_header* )block->pre_block;
				if( temp != NULL ){
					temp->next_block = block->next_block;
					temp = block->next_block;
					if( temp != NULL  ){
						temp->pre_block = block->pre_block;
					}
				}else{
					blocks.blk_idle = block->next_block;
					if( blocks.blk_idle ){
						((page_header  *)blocks.blk_idle)->pre_block = NULL;
					}
				}
				blocks.blk_idle_cnter--;
			}
			break;
		case BLOCK_LAZY :
			if( blocks.blk_old_cnter > 0 ){
				temp = ( page_header* )block->pre_block;
				if( temp != NULL ){
					temp->next_block = block->next_block;
					temp = block->next_block;
					if( temp != NULL  ){
						temp->pre_block = block->pre_block;
					}
				}else{
					blocks.blk_old = block->next_block;
					if( blocks.blk_old ){
						((page_header  *)blocks.blk_old)->pre_block = NULL;
					}
				}
				blocks.blk_old_cnter--;
			}
			break;
		default:
			temp = ( page_header* )block->pre_block;
			if( temp != NULL ){
				temp->next_block = block->next_block;
				temp = block->next_block;
				if( temp != NULL  ){
					temp->pre_block = block->pre_block;
				}
			}else{
				temp = block->next_block;
				if( temp ){
					((page_header  *)temp)->pre_block = NULL;
				}
			}
			break;
		}
		block->next_block = NULL;
		block->pre_block = NULL;
	}
	return 1;
}
/*d*/
/*************************************************************************
* 関 数 名 : get_father
* 機    能 : ページの親のアドレスを取る
* 引 き 数 : page： 子ページ
* 戻 り 値 : 親ページのアドレス
* 詳細内容 :
************************************************************************/

static void* get_father( page_header *page )
{
	S4 offsetsize;
	S4 pagetimes;
	VOID * father;

	if( page == NULL || (void*)page < page->p_block )
	{
		return NULL;
	}
	offsetsize = (CHAR*)page - (CHAR*)page->p_block;
	pagetimes = offsetsize/page_info[page->page_size].page_size;

	if( ( pagetimes & 0x1UL ) == 0 )
	{
		father =  (VOID*)page;
	}
	else
	{
		father = (VOID*)( (CHAR *)page - page_info[page->page_size].page_size );
	}
	return father;
}
/*d*/
/*************************************************************************
* 関 数 名 : get_swap_filename
* 機    能 : 中間ファイルのパスを作成
* 引 き 数 : pBufOwner：ユーザ側のID
* 戻 り 値 : CHAR *
* 詳細内容 :ユーザ側のIDずつ、唯一のファイル名を作る。
************************************************************************/

static CHAR* get_swap_filename( buffer_owner_info *pBufOwner )
{
	if( pBufOwner == NULL || pBufOwner->procid == 0 )
	{
		return NULL;
	}
	sprintf( szName, "%s_%lu_%d.x", szName_Prefix, pBufOwner->procid, pBufOwner->index );
	strcpy( szFilePath, szPath );
	strcat( szFilePath, szName );
	return(szFilePath);
}

/**************************************************************************
* 関 数 名 : resetmemory
* 機    能 : 古いデータをスワップアウトする
* 引 き 数 : なし
* 戻 り 値 : U4        1              正常終了
*          :           0             異常終了
* 詳細内容 :blocks.block_oldのブロックのデータをスワップアウトし、そのブロックを
*           blocks.block_idleに繋ぐ
************************************************************************/

static BOOL	resetmemory( VOID )
{
	VOID *block;
	VOID *preblock = 0;
//	VOID* temp_old;
	VOID* data;
	CHAR * binfile;

	block = blocks.blk_old;
	while( block )
	{
		if( preblock == block ){
			break;
		}
		binfile = get_swap_filename( &getheader(block)->buf_owner );
		if( binfile == NULL )
		{
			return ( 0 );
		}
		data = (char*)block + HEADER_SIZE;
		if( !data2file( binfile, data, gblBlock_size ) )
		{
			return ( 0 );
		}
		preblock = block;
		InformReset(&getheader(block)->buf_owner );
//		temp_old = getheader(block)->next_block;
		addBlock( block, BLOCK_IDLE );
		move_block( block );
		block = blocks.blk_old;
	}
	return( 1 );
}
/**************************************************************************
* 関 数 名 : allocmemory
* 機    能 : 指定ﾊﾞｲﾄ数のﾒﾓﾘ領域を確保
* 引 き 数 : VOID      **ppvArea           確保した領域を返すﾎﾟｲﾝﾀ
*          : U4       ulSize            領域確保ｻｲｽﾞ
* 戻 り 値 : U4        1              正常終了
*          :           0             異常終了
* 詳細内容 :malloc  ->  memset(0)
************************************************************************/

static BOOL	allocmemory( VOID **ppvArea, U4 ulSize )
{
	CHAR		**pp;		/* ﾜｰｸﾎﾟｲﾝﾀ			*/

	if( ppvArea == NULL )
	{
		return (0);
	}
	pp = (CHAR**)ppvArea;
	*pp = (CHAR*)malloc( (size_t)ulSize );
	return( *pp != (VOID*)0 );
}

/**************************************************************************
* 関 数 名 : new_page
* 機    能 : 指定サイズのページを取る
* 引 き 数 : S2       idx          サイズテーブルのインデックス
*       : VOID **       page            確保するページのアドレス
* 戻 り 値 : U4        1              正常終了
*          :        0             異常終了
************************************************************************/
static BOOL new_page( S2 idx, VOID ** page )
{
	VOID * parentpage;
	int parentidx = idx + 1;

	if( idx > FLG_BIT_NUM )
	{
		return 0;
	}
	else if( idx == FLG_BIT_NUM )
	{
		return new_block(page);
	}
	else
	{
		if( page_info[idx].page_free != NULL )
		{
			*page = page_info[idx].page_free;
			page_info[idx].page_free = getheader(*page)->next_page;
			if( page_info[idx].page_free )
		    {
				getheader( page_info[idx].page_free )->pre_page = NULL;
		    }
			parentpage = get_father(*page);
		}
		else
		{
			if( !new_page (idx+1, &parentpage ) )
			{
			    return 0;
		    }
			*page = parentpage;

			page_info[idx].page_free = (CHAR*)parentpage + page_info[idx].page_size;
			getheader(page_info[idx].page_free)->page_size = idx;
			getheader(page_info[idx].page_free)->ul_firstflg = 0;
			getheader(page_info[idx].page_free)->ul_secondflg = 0;
			getheader(page_info[idx].page_free)->p_block = getheader(parentpage)->p_block;
			getheader(page_info[idx].page_free)->_BLOCK_HEAD_ = _BLOCK_HEADER_STRING_;
			getheader(page_info[idx].page_free)->pre_page = NULL;
			getheader(page_info[idx].page_free)->next_page = NULL;
			getheader(page_info[idx].page_free)->buf_owner.procid = 0;
		}
		getheader(*page)->next_page = NULL;
		getheader(*page)->pre_page = NULL;
		getheader(*page)->p_block = getheader(parentpage)->p_block;
		getheader(*page)->page_size = idx;
		while( idx >= 0 )
		{
			getheader(*page)->ul_firstflg &= ~page_info[idx].bit_mask;
			getheader(*page)->ul_secondflg &= ~page_info[idx].bit_mask;
			idx --;
		}
		getheader(*page)->_BLOCK_HEAD_ = _BLOCK_HEADER_STRING_;

		if( parentpage == *page )
		{
			getheader(parentpage)->ul_firstflg |= page_info[parentidx].bit_mask;
		}
		else
		{
			getheader(parentpage)->ul_secondflg |= page_info[parentidx].bit_mask;
		}
		return( (*page ) != NULL );
	}
}
/**************************************************************************
* 関 数 名 : new_block
* 機    能 : 新しいメモリブロックを確保する
* 引 き 数 : VOID      **page           確保した領域を返すﾎﾟｲﾝﾀ
* 戻 り 値 : BOOL        1              正常終了
*          :        0             異常終了
************************************************************************/
static BOOL new_block(  VOID ** page )
{
	page_header  *pblock;
	VOID *newMem;
	UCHAR bResetFlg = 0;

	if( blocks.blk_idle == NULL || blocks.blk_idle_cnter == 0 )
	{
		if( max_mem_volumn == 0 )
		{
			if( !allocmemory( &newMem, BLOCK_SIZE ) )
			{
				/* failed */
				bResetFlg = 1;
			}
			else
			{
				cur_mem_volumn++;
			}
		}
		else if( cur_mem_volumn >= max_mem_volumn )
		{
			/* failed */
			bResetFlg = 1;
		}
		else
		{
			if( !allocmemory( &newMem, BLOCK_SIZE ) )
			{
				/* failed */
				bResetFlg = 1;
			}
			else
			{
				cur_mem_volumn++;
			}
		}
		if( bResetFlg == 1 )
		{
			/* failed */
			if( !resetmemory() )
			{
				return 0;
			}
		}
		else
		{
			/* new */
			memset( newMem, 0 , BLOCK_SIZE );
			addBlock(  (page_header  *)newMem, BLOCK_IDLE );
		}
	}
	pblock = (page_header  *)blocks.blk_idle;
	if( pblock != NULL )
	{
		move_block( pblock );
		addBlock( pblock, BLOCK_BUSY );
		getheader(pblock)->_BLOCK_HEAD_ = _BLOCK_HEADER_STRING_;
		* page = (VOID *)pblock;
		getheader(*page)->p_block = * page;
		getheader(*page)->page_size = FLG_BIT_NUM;
	}
	else
	{
		*page = NULL;
	}
	return (* page != NULL );
}
/**************************************************************************
* 関 数 名 : free_page
* 機    能 : 指定されたページを回収する
* 引 き 数 :page_header* page          ページの管理情報へのポインタ
* 戻 り 値 : BOOL        1              正常終了
*          :          0             異常終了
************************************************************************/
static BOOL free_page( page_header* page )
{
	page_header * father;
	VOID * temp;
	S2 fatheridx;


	if( page->page_size == FLG_BIT_NUM  )
	{
		return free_block( page );
	}
	father = get_father(page);
	if( father == NULL  )
	{
		return 0;
	}

	fatheridx = page->page_size + 1;
	if( page == father )	/* first half */
	{

		father->ul_firstflg &= ~page_info[fatheridx].bit_mask;

		if( father->ul_secondflg & page_info[fatheridx].bit_mask )
		{
			/* second half is being used. Connect to page_free */
			temp = page_info[page->page_size].page_free;
			page_info[page->page_size].page_free = page;
			page->next_page = temp;
			if( temp )
			{
				getheader(temp)->pre_page = page;
			}
		}
		else
		{
			/* second half is not being used. give back to father*/
			/* before it, remove the page for the in-use chain */
			temp = (CHAR*)father + page_info[page->page_size].page_size;
			assert( getheader(temp)->page_size == page->page_size  );
			move_page_inuse( temp );
			father->page_size = fatheridx;
			return free_page(father);
		}
	}
	else
	{/* second half */
		father->ul_secondflg &= ~page_info[fatheridx].bit_mask;
		if( father->ul_firstflg & page_info[fatheridx].bit_mask )
		{
			/* first half is being used. Connect to page_free */
			temp = page_info[page->page_size].page_free;
			page_info[page->page_size].page_free = page;
			page->next_page = temp;
			if( temp )
			{
				getheader(temp)->pre_page = page;
			}
		}
		else
		{
			/* first half is not being used. give back to father*/
			/* before it, remove the page for the in-use chain */
			move_page_inuse( father );
			father->page_size = fatheridx;
			return free_page(father);
		}
	}
	return 1;
}
/**************************************************************************
* 関 数 名 : free_block
* 機    能 : ブロックを回収する
* 引 き 数 : page_header* block ブロックの管理情報へのポインタ
* 戻 り 値 : BOOL        1              正常終了
*          :          0             異常終了
************************************************************************/
static BOOL free_block( page_header* block )
{
	move_block(block);
	addBlock( block, BLOCK_IDLE );
	return 1;
}

/**************************************************************************
* 関 数 名 : move_page_inuse
* 機    能 : 双方向チェーンからブロックを取り除く
* 引 き 数 : page_header* page ページの管理情報へのポインタ
* 戻 り 値 : BOOL        1              正常終了
*          :          0             異常終了
************************************************************************/
static BOOL move_page_inuse( page_header* page )
{
	page_header * temp;
	S2 idx;

	if( page != NULL )
	{
		idx = page->page_size;
		temp = page_info[idx].page_free;
		if( temp == page )
		{
			/* first one */
			temp = page->next_page;
			page_info[idx].page_free = temp;
			if( temp )
			{
				temp->pre_page = NULL;
	       	}
		}
		else if( page->pre_page || page->next_page )
		{
			/* others */
			temp = (page->pre_page);
			if( temp != NULL )
			{
				temp->next_page = page->next_page;
				temp = page->next_page;
				if( temp != NULL )
				{
					temp->pre_page = page->pre_page;
				}
			}
		}
		page->next_page = NULL;
		page->pre_page = NULL;
	}
	return 1;
}
/*d*/
/*************************************************************************
* 関 数 名 : file2data
* 機    能 : 確保したﾒﾓﾘ領域を中間ファイルから読み出す
* 引 き 数 :
* 		page：メモリへのポインタへのポインタ
* 		ulSize：メモリデータのサイズ。
* 		pszFile:中間ファイル名
* 戻 り 値 : 1:成功
* 		  0:失敗
************************************************************************/
static BOOL	file2data( VOID	*page,  CHAR * pszFile, U4 ulSize )
{
	FILE	*pf;
	U4 siz;

	if( pszFile == NULL )
	{
		return (0);
	}
	if( *pszFile == '\0' )
	{
		return(0);
	}
	if( page == NULL )
	{
		return (0);
	}
	if( ulSize == 0 )
	{
		return (0);
	}
	lSwapOutCnt--;
	pf  = fopen( pszFile, BIN_FILE_READ );
	if( pf == NULL )
	{
		return ( 0 );
	}
	siz = fread( (CHAR*)( page ), 1, ulSize, pf );
	if( siz != ulSize )
	{
		fclose(pf);
		return ( 0 );
	}
	fclose(pf);
	remove(pszFile);
	return(1);
}
/*d*/
/*************************************************************************
* 関 数 名 : data2file
* 機    能 : メモリ中のデータをファイルに保存
* 引 き 数 :pszFile:中間ファイル名
* 		page：メモリへのポインタへのポインタ
* 		ulSize：メモリデータのサイズ。
* 戻 り 値 : 1:成功
* 		  0:失敗
************************************************************************/
static BOOL	data2file( CHAR * pszFile, VOID	*page, U4 ulSize )
{
	FILE	*pf;
	U4 siz;

	if( pszFile == NULL )
	{
		return (0);
	}
	if( *pszFile == '\0' )
	{
		return(0);
	}
	if( page == NULL )
	{
		return (0);
	}
	if( ulSize == 0 )
	{
		return (0);
	}
	lSwapOutCnt++;
	pf  = fopen( pszFile, BIN_FILE_WRITE );
	if( pf == NULL )
	{
		return ( 0 );
	}
	siz = fwrite( (CHAR*)( page ), 1, ulSize, pf );
	if( siz != ulSize )
	{
		fclose(pf);
		return ( 0 );
	}
	fclose(pf);

	return(1);
}
/*d*/
/*************************************************************************
* 関 数 名 : memFile2Mem
* 機    能 : 確保したﾒﾓﾘ領域を中間ファイルから読み出す
* 引 き 数 : page_offset　ページの（ユーザ側に公開する）アドレス
* 		　　pBufOwner　ユーザ側のID
* 　　　　　　　　ulSize　データのサイズ
* 戻 り 値 : 1:成功
* 		  0:失敗
* 詳細内容 :
************************************************************************/

static BOOL	memFile2Mem( VOID * page_offset,  buffer_owner_info *pBufOwner, U4 ulSize  )
{
	CHAR *	binfile;
//	VOID * page;

	if( pBufOwner == NULL || page_offset == NULL )
	{
		return ( 0 );
	}
//	page = (VOID*)((CHAR*)(page_offset) - HEADER_SIZE );
	/*ulSize+=HEADER_SIZE;*/
	binfile = get_swap_filename( pBufOwner );
	if( binfile == NULL )
	{
		return ( 0 );
	}
	if( !(file2data( page_offset, binfile, ulSize )) )
	{
		return (0);
	}
	remove(binfile);
	return 1;
}

/************************************************************************
* 関 数 名 : memInitial
* 機    能 : メモリ管理モジュール初期化
* 引 き 数 : pszFolder: 中間ファイルの保存先
* 		ulMb: 確保できる最大メモリ
* 戻 り 値 : BOOL        TRUE              正常終了
*          :          FALSE             異常終了
* 詳細内容 : 配ったメモリを管理するデータを作成
************************************************************************/

static BOOL	memInitial( CHAR * tempfolder, U4 ulDefinedMb )
{
	S4   astMem;
	struct _filestat sbuf;
	S4 i;
	const CHAR * TEMP_FOLDER_KEY = "TEMP";
	time_t tm;
	/* テンポラリファイルの出力先   start */
	if( tempfolder != NULL )
	{
		strcpy( szPath, tempfolder );
		astMem = strlen(szPath);
		if( ( getfilestat( szPath, &sbuf ) ) || astMem >= (S4)( OS_FULLPATH - sizeof(szName) ) || !IS_FOLDER(sbuf))
		{
			if( getenv( TEMP_FOLDER_KEY) != NULL )
			{
				strcpy( szPath, getenv( TEMP_FOLDER_KEY) );
			}
			else
			{
				return 0 ;
			}
		}
	}
	else
	{
		if( getenv( TEMP_FOLDER_KEY) != NULL )
		{
			strcpy( szPath, getenv( TEMP_FOLDER_KEY) );
		}
		else
		{
			return 0 ;
		}
	}
	astMem = strlen(szPath);
	if( !( getfilestat( szPath, &sbuf ) ) && astMem < (S4)( OS_FULLPATH - sizeof(szName) ) && IS_FOLDER(sbuf) )
	{
		szPath[astMem] = '\\';
		szPath[astMem+1] = '\0';
	}
	else
	{
		return 0;
	}
	/* テンポラリファイルの出力先   end */

	/* メモリ使用制限   start */
	if( ulDefinedMb > 0 )
	{
		/* 固定領域のメモリの管理ブロック */
		if( ulDefinedMb < MIN_MEM_SIZE )
		{
			ulDefinedMb = MIN_MEM_SIZE;
		}
		max_mem_volumn = GET_DEF_LIMIT(ulDefinedMb);
	}
	else
	{
		max_mem_volumn = 0;
	}
	cur_mem_volumn = 0;
	/* メモリ使用制限   end */
	/* Page管理情報初期化 start*/
	page_info[0].page_free = NULL;
	page_info[0].page_size = (MIN_PAGE_SIZE);
	page_info[0].bit_mask = (1UL);
	for( i = 1 ; i <= FLG_BIT_NUM; i++ )
	{
		page_info[i].page_free = NULL;
		page_info[i].page_size = (MIN_PAGE_SIZE)<<i;
		page_info[i].bit_mask = ( (1UL)<<i );
	}
	blocks.blk_idle = NULL;
	blocks.blk_idle_cnter = 0;
	blocks.blk_in_use = NULL;
	blocks.blk_in_use_cnter = 0;
	blocks.blk_old = NULL;
	blocks.blk_old_cnter = 0;
	/* Page管理情報初期化 end  */
	/* owner情報初期化 start*/
	if( NULL == newOwnerPage() )
	{
		return 0;
	}
	ownBufOffset = 0;
	/* owner情報初期化 end*/
	tm = time(NULL);
	sprintf( szName_Prefix, "core%ld", tm );
	initial_flag = 1;
	lSwapOutCnt = 0;
	return (1);
}
/*D*/

/************************************************************************
* 関 数 名 : memTerminate
* 機    能 : メモリ管理モジュール終了
* 引 き 数 : なし
* 戻 り 値 : なし
* 詳細内容 : 配ったメモリを管理するデータを削除
************************************************************************/

static VOID  	memTerminate( VOID )
{
	page_header * pages;
	page_header * freepage;
	owner_buffer_header * p;
	if( initial_flag != 0 )
	{
		pages = (page_header *)blocks.blk_idle;
		while( pages != NULL && blocks.blk_idle_cnter > 0 )
		{
			freepage = pages;
			pages = pages->next_block;
			free( (VOID*)freepage );
			blocks.blk_idle_cnter--;
		}
		blocks.blk_idle = NULL;
		pages = (page_header *)blocks.blk_in_use;
		while( pages != NULL && blocks.blk_in_use_cnter > 0 )
		{
			freepage = pages;
			pages = pages->next_block;
			free( (VOID*)freepage );
			blocks.blk_in_use_cnter--;
		}
		blocks.blk_in_use = NULL;
		pages = (page_header *)blocks.blk_old;
		while( pages != NULL && blocks.blk_old_cnter > 0 )
		{
			freepage = pages;
			pages = pages->next_block;
			free( (VOID*)freepage );
			blocks.blk_old_cnter--;
		}
		blocks.blk_old = NULL;
	}
	ownBufOffset = 0;
	ownerNum =0;
	while( owner_buffer != NULL )
	{
		p = owner_buffer->next;
		free( (VOID*)owner_buffer );
		owner_buffer = p;
	}
}


/*D*/
/************************************************************************
* 関 数 名 : memPagesize
* 機    能 : あるページに対して、ページのサイズを返す
* 引 き 数 :page_offset　ページの（ユーザ側に公開する）アドレス

* 戻 り 値 :bytes
************************************************************************/
static U4	memPagesize( VOID *page_offset )
{
	page_header * page;

	if( page_offset == NULL )
	{
		return 0;
	}

	page = (page_header*)((CHAR*)(page_offset) - HEADER_SIZE );

	return (page_info[page->page_size].page_size);
}
/*D*/
/************************************************************************
* 関 数 名 : MemSetOldPage
* 機    能 :データブロックに古いデータフラグをつける
* 引 き 数 :page_offset　ページの（ユーザ側に公開する）アドレス

* 戻 り 値 :なし
************************************************************************/
VOID MemSetOldPage( VOID *page_offset )
{
	page_header * page;
	if( page_offset != NULL )
	{
		page = (page_header*)((CHAR*)(page_offset) - HEADER_SIZE );
		if( page->buf_owner.procid > 0 )
		{
			move_block( page );
			addBlock( page, BLOCK_LAZY );
		}
	}
}

/*d*/
/*************************************************************************
* 関 数 名 : newOwnerPage
* 詳細内容 :
************************************************************************/
static owner_buffer_header * newOwnerPage( VOID )
{
	owner_buffer_header * p;
	owner_buffer_header ** p2;
	p = (owner_buffer_header*)malloc( (size_t)owner_buffer_alloc_size );
	if( p == NULL ){
		return NULL;
	}
	memset( p, 0 , owner_buffer_alloc_size );
	p->next = NULL;
	p->buffer = (CHAR*)p + ownbuf_headersize;
	p2 = & owner_buffer;
	while( *p2 != NULL )
	{
		p2 = &((*p2)->next);
	}
	*p2 = p;
	ownerNum++;
	return p;
}
/*d*/
/*************************************************************************
* 関 数 名 : InformReset
* 詳細内容 :
************************************************************************/
static owner_buffer_header * getCurrOwnerPage( U4 offset )
{
	U4 idx = offset / owner_buffer_size;
	owner_buffer_header * p;

	p = owner_buffer;
	while( idx > 0 )
	{
		p = p->next;
	}
	return p;
}
static VOID InformReset( buffer_owner_info * p_owner )
{
	if( p_owner != NULL )
	{
		if( p_owner->resetListener != NULL )
		{
			p_owner->resetListener( p_owner->procid, p_owner->index );
		}
	}
}
/*D*/
/************************************************************************
* 関 数 名 : memIsValidPage
* 機    能 :データページは回収されたかを確認する。
* 引 き 数 :page_offset　ページの（ユーザ側に公開する）アドレス
　　　　　　　　owner　ユーザ側のID
* 戻 り 値 :0  回収済み。　使用不可
* 　　　　　　　1　　未回収　　使用可能
************************************************************************/
BOOL MemIsValidPage( VOID *page_offset,  buffer_owner_info* owner )
{
	page_header * page;
	if( page_offset != NULL && owner != NULL )
	{
		page = (page_header*)((CHAR*)(page_offset) - HEADER_SIZE );
		if( page->buf_owner.procid == owner->procid
			&& page->buf_owner.index == owner->index )
		{
			return 1;
		}
	}
	return 0;
}
/*D*/
/************************************************************************
* 関 数 名 : MemManInitial
* 機    能 : メモリ管理モジュール初期化
* 引 き 数 : usFlg  各テーブルのメモリ量を記録するかのフラグ
* 			ulMb　　最大のメモリ量（MB)
* 戻 り 値 : BOOL        TRUE              正常終了
*          :             FALSE             異常終了
* 詳細内容 : 配ったメモリを管理するデータを作成
************************************************************************/

BOOL MemTblInitial( CHAR * tempfolder, U2 usFlg, U2 ulMb )
{
	if( initial_flag == 1 )
	{
		return TRUE;
	}
	gblRecordTableByte = usFlg;
	cur_mem_in_use = 0;
	return( memInitial( tempfolder, ulMb ));
}

/*D*/
/************************************************************************
* 関 数 名 : MemTblTerminate
* 機    能 : メモリ管理モジュール終了
* 引 き 数 : なし
* 戻 り 値 : BOOL        TRUE              正常終了
*          :             FALSE             異常終了
* 詳細内容 : 配ったメモリを管理するデータを削除
************************************************************************/

VOID  MemTblTerminate( VOID )
{
	if( initial_flag == 0 )
	{
		return;
	}
	if( lSwapOutCnt )
	{
		FILEFIND stFind ;
		S4 ret ;
		PSZ filename;
		ret = FileFindOpen(szPath, &stFind);
		if( ret == COEXIT_SUCCESS )
		{
			ret = FileFindFirst( &stFind );
			while( ret == COEXIT_SUCCESS )
			{
				filename = FilePickUpName( stFind.szFound );
				if( strncmp( filename, szName_Prefix, strlen(szName_Prefix) ) == 0 )
				{
					remove(stFind.szFound);
				}
				ret = FileFindNext( &stFind );
			}
			FileFindClose( &stFind );
		}
	}
	cur_mem_in_use = 0;
	memTerminate( );

}
/*D*/
/************************************************************************
* 関 数 名 : memNewMemory
* 機    能 : 要求されたサイズのページを用意する
* 引 き 数 :   ulSize　：　要求されたページサイズ
* 			ppvBlock: 該当するメモリのブロックを返す（ユーザ側に公開するアドレス）
* 		  ppBufOwner：返したメモリブロックのユーザ側のIDを保存するエリア。
* 戻 り 値 :0:エラー
*       1:正常
************************************************************************/
BOOL	MemNewMemory( U4 ulSize, VOID ** ppvBlock, buffer_owner_info ** ppBufOwner )
{
	VOID *pvT;
	BOOL bRet;
	U4 ulMemSetSize;
	S2 nSizeIndex;
	if( initial_flag == 0 )
	{
		return 0;
	}
	if( ulSize == 0 )
	{
		return 1;
	}
	if( ppvBlock == NULL )
	{
		return 0;
	}
	ulSize += HEADER_SIZE;
	if( ulSize > BLOCK_SIZE )
	{
		return 0;
	}
	for( nSizeIndex = 0 ; nSizeIndex <= FLG_BIT_NUM; nSizeIndex++ )
	{
		if( ulSize <= page_info[nSizeIndex].page_size )
		{
			break;
		}
	}
	if( nSizeIndex > FLG_BIT_NUM )
	{
		return 0;
	}
	else if( nSizeIndex == FLG_BIT_NUM )
	{
		bRet = new_block( &pvT );
	}
	else
	{
		bRet = new_page( nSizeIndex, &pvT );
	}

	if( !bRet )
	{
		return 0;
	}
	if( ppBufOwner != NULL )
	{
		*ppBufOwner = &((page_header*)pvT)->buf_owner;
		(*ppBufOwner)->index = 0;
		(*ppBufOwner)->procid = 0;
		(*ppBufOwner)->resetListener = NULL;
	}

	*ppvBlock = (VOID*)((CHAR*)pvT + HEADER_SIZE );
	cur_mem_in_use += page_info[nSizeIndex].page_size;
	ulMemSetSize = page_info[nSizeIndex].page_size - HEADER_SIZE;
	memset( *ppvBlock, 0, (size_t)ulMemSetSize );
	return 1;
}
/*D*/
/************************************************************************
* 関 数 名 : memReallocMemory
* 機    能 : 要求されたサイズのページを再配置する
* 引 き 数 :　　 ulSize　：　要求されたページサイズ
* 			ppvBlock: 該当するメモリのブロックを返す（ユーザ側に公開するアドレス）
* 		  ppBufOwner：返したメモリブロックのユーザ側のIDを保存するエリア。
* 戻 り 値 :0:エラー
*       1:正常
************************************************************************/
BOOL	MemReallocMemory( U4 ulSize, VOID ** ppvBlock, buffer_owner_info ** ppBufOwner )
{
	page_header *page;
	buffer_owner_info bufOwner;
	VOID *pvT = 0;
	S2 nSizeIndex;
	U4 ulSize_old;
	BOOL bRet;

	if( initial_flag == 0 )
	{
		return 0;
	}
	if( ppvBlock == NULL )
	{
		return 0;
	}

	if( *ppvBlock == NULL )
	{
		return MemNewMemory(ulSize, ppvBlock, ppBufOwner);
	}
	ulSize += HEADER_SIZE;
	if( ulSize > BLOCK_SIZE )
	{
		return 0;
	}
	page = (page_header *)((CHAR*)(*ppvBlock) - HEADER_SIZE );
	ulSize_old = page_info[page->page_size].page_size;
	if( ulSize_old >= ulSize )
	{
		if( ppBufOwner != NULL )
		{
			*ppBufOwner = &((page_header*)page)->buf_owner;
		}
		return 1;
	}
	cur_mem_in_use -= ulSize_old;
	for( nSizeIndex = 0 ; nSizeIndex <= FLG_BIT_NUM; nSizeIndex++ )
	{
		if( ulSize <= page_info[nSizeIndex].page_size )
		{
			break;
		}
	}

	bufOwner = page->buf_owner;
	InformReset( &bufOwner );
	if( !free_page(page))
	{
		return 0;
	}
	if( nSizeIndex > FLG_BIT_NUM )
	{
		return 0;
	}
	else if( nSizeIndex == FLG_BIT_NUM )
	{
		bRet = new_block( &pvT );
	}
	else
	{
		bRet = new_page( nSizeIndex, &pvT );
	}
	if( !bRet )
	{
		return 0;
	}
	cur_mem_in_use += page_info[nSizeIndex].page_size;
	*ppvBlock = (VOID*)((CHAR*)pvT + HEADER_SIZE );
	page->buf_owner.index = 0;
	page->buf_owner.procid = 0;
	if( pvT != page )
	{
		if(!memcpy( *ppvBlock , (VOID*)((CHAR *)page + HEADER_SIZE), ulSize_old - HEADER_SIZE ))
		{
			return 0;
		}
		getheader(pvT)->buf_owner = bufOwner;

	}

	memset( (CHAR*)*ppvBlock + (ulSize_old-HEADER_SIZE), 0, page_info[nSizeIndex].page_size - ulSize_old );
	if( ppBufOwner != NULL )
	{
		*ppBufOwner = &((page_header*)pvT)->buf_owner;
		(*ppBufOwner)->index = 0;
		(*ppBufOwner)->procid = 0;
		(*ppBufOwner)->resetListener = NULL;
	}
	return 1;
}
/*D*/
/************************************************************************
* 関 数 名 : memFreeMemory
* 機    能 : 1つのメモリページを解放
* 引 き 数 :
* 		  pBlock：ページの（ユーザ側に公開する）アドレス
* 戻 り 値 :0:エラー
*       1:正常
************************************************************************/
BOOL	MemFreeMemory( VOID **pBlock )
{
	page_header * header;

	if( pBlock == NULL || *pBlock == NULL )
	{
		return 1;
	}
	header = (page_header *)((CHAR*)(*pBlock) - HEADER_SIZE );
	InformReset( &header->buf_owner );
	header->buf_owner.index = 0;
	header->buf_owner.procid = 0;
	*pBlock = NULL;
	cur_mem_in_use -= page_info[header->page_size].page_size;
	return free_page(header);
}
/*d*/
/*************************************************************************
* 関 数 名 : MemTblSwapInTable
* 機    能 : テーブルにメモリを確保
* 引 き 数 : pCtrl		管理データへのポインタ
* 			astHeaderNo
* 戻 り 値 : BOOL
* 詳細内容 :
************************************************************************/
VOID * MemTblSwapInTable( U4 u4Idx, U2 headerno, buffer_owner_info ** ppBufOwner )
{
	VOID*	pvTab = NULL;
	buffer_owner_info * p_owner;

	if( !initial_flag )
	{
		return FALSE;
	}

	if( !MemNewMemory( gblBlock_size, &pvTab, &p_owner ) )
	{
		return FALSE;
	}
	p_owner->index = headerno + 1;
	p_owner->procid = u4Idx;
	p_owner->resetListener = NULL;
	if( ppBufOwner )
	{
		*ppBufOwner = p_owner;
	}
	memset( pvTab, 0, (size_t)gblBlock_size );
	MemSetOldPage(pvTab);
	if( ! memFile2Mem( pvTab, p_owner, gblBlock_size ) )
	{
		return NULL;
	}
	return pvTab;
}
/*d*/
/*************************************************************************
* 関 数 名 : MemGetPagesize
* 機    能 : Pageサイズ取得
* 戻 り 値 : サイズ
* 詳細内容 :
************************************************************************/
U4	MemGetPagesize( VOID *page_offset )
{
	U4 ulSize;
	ulSize = memPagesize( page_offset );
	return (ulSize > HEADER_SIZE?(ulSize - HEADER_SIZE):0);
}
/*d*/
/*************************************************************************
* 関 数 名 : MemGetBlockSize
* 機    能 : blockサイズを取る。
* 引 き 数 :
* 戻 り 値 : サイズ
* 詳細内容 :
************************************************************************/
U4	MemGetBlockSize( VOID )
{
	return (U4)(gblBlock_size);
}

/*d*/
/*************************************************************************
* 関 数 名 : MemRegisiter
* 機    能 : ownerを登録する
* 引 き 数 :
* 戻 り 値 : ID >0
*     0 失敗
* 詳細内容 :
************************************************************************/
U4	MemRegisiter( PSZ str )
{
	U4 len = str_length( str );
	U4 id = 0;
	owner_buffer_header *p = NULL;
	if( initial_flag == 0 )
	{
		if( !MemTblInitial( NULL, 0, 0 ) )
		{
			return 0;
		}
	}
	if( len == 0 )
	{
		return 0;
	}
	if( len > owner_name_max_length )
	{
		/* 悪攻撃防止  */
		str = (CHAR*)str + len - owner_name_max_length;
		len = owner_name_max_length;
	}
	len += 2;  /* space of owner validation key and '\0' */
    id = ownBufOffset + 1;
    ownBufOffset += len;
    if( ownBufOffset > ownerNum * owner_buffer_size )
    {
    	p = newOwnerPage();
    	if( p == NULL )
    	{
    		return 0;
    	}
    	ownBufOffset = ownerNum * owner_buffer_size + len;
    	id = ownerNum * owner_buffer_size;
    }
    else
    {
    	p = getCurrOwnerPage( ownBufOffset );
    	if( p == NULL )
    	{
    		return 0;
    	}
    }
    p->buffer[id%owner_buffer_size] = owner_validation_key;
    strcpy( &p->buffer[id%owner_buffer_size + 1], str );
    p->buffer[ownBufOffset%owner_buffer_size] = '\0';
    return id;
}
/* D */
PSZ MemGetTblRegister( U4 idx )
{
	owner_buffer_header *p = getCurrOwnerPage( idx );
	return &p->buffer[idx%owner_buffer_size];
}
/* D */
U4 MemGetMaxSize( VOID )
{
	return cur_mem_volumn*BLOCK_SIZE;
}
/* D */
U4 MemGetUsefulSize( VOID )
{
	return cur_mem_in_use;
}
U4 MemGetIdleBlockNumber( VOID )
{
	return blocks.blk_idle_cnter;
}
U4 MemGetBusyBlockNumber( VOID )
{
	return blocks.blk_in_use_cnter;
}
U4 MemGetLazyBlockNumber( VOID )
{
	return blocks.blk_old_cnter;
}
VOID MemReleaseUnusedMem( VOID )
{
	page_header * pages;
	while( lSwapOutCnt < blocks.blk_idle_cnter ){
		pages = (page_header *)blocks.blk_idle;
		if( pages != NULL && blocks.blk_idle_cnter > 0 ){
			move_block( pages );
			free( (VOID*)pages );
			blocks.blk_idle_cnter--;
			cur_mem_volumn--;
		}
	}
}

#endif
/* end of file */
